﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities;
using JTLeigh.Commerce.Spencer.Features.ProductFeedback.Data.Providers;
using ProductFeedbackE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductFeedback;
using JTLeigh.Commerce.Spencer.Core.Testing;
using JTLeigh.Commerce.Spencer.Core.Testing.Mocks.Data;

namespace JTLeigh.Commerce.Spencer.Features.ProductFeedback.Data.UnitTests.Providers
{

	/// <summary>
	/// Unit tests for the <see cref="ProductFeedbackProvider"/> class.
	/// </summary>
	[TestClass]
	public class ProductFeedbackProviderFixture
	{

		#region Inner Classes and Types

		private static class Constants
		{

			public static class ProductFeedback
			{

				public static class FeedbackId
				{
					public static readonly Guid Feedback1 = new Guid("7E1ABE09-FD0F-404A-B4DC-ADD61EE9E6F1");
					public static readonly Guid Feedback2 = new Guid("57A38A0B-A7B6-4915-98CA-ED3635F0BC1E");
				}

			}

			// FIXME: Move this.
			public static class ProductRatingAttribute
			{

				public static class AttributeId
				{
					public static readonly Guid ImageQuality = new Guid("21828F07-BFF4-4c96-872A-D7CD055340E4");
					public static readonly Guid SoundQuality = new Guid("3A993AE2-BDB9-4336-B953-ABC19991C2FF");
				}

			}

			// FIXME: Move this.
			public static class ProductRecommendationAttribute
			{

				public static class AttributeId
				{
					public static readonly Guid FamilyMember = new Guid("B004E867-4876-403f-827E-D30852E81D7C");
					public static readonly Guid Friend = new Guid("A36552C6-59AE-4252-89B4-72109A9BF5C3");
				}

			}

			// FIXME: Move this.
			public static class ProductReviewAttribute
			{

				public static class AttributeId
				{
					public static readonly Guid Pros = new Guid("DEFD2F7D-8355-45d1-A4D9-796D9FCDDA11");
					public static readonly Guid Cons = new Guid("042A0ED1-0937-4f1d-94FD-BE342AD5231F");
				}

			}

            public static class ProductReviewImage
            {

                public static class ImageId
                {
                    public static readonly Guid ProductInSunlight = new Guid("9365DA9F-2108-43B8-A885-71033F1B33D8");
                    public static readonly Guid ProuctInLowLight = new Guid("D4455EC9-F785-47F1-B4F2-F2910FB228C0");
                }

            }

		}

		private static class StoredProcedure
		{

			public static class GetProductFeedback
			{

				public static class Table
				{

					public static readonly DataTable ProductFeedback;
					public static readonly DataTable ProductRating;
					public static readonly DataTable ProductRatingAttributeValue;
					public static readonly DataTable ProductRecommendation;
					public static readonly DataTable ProductRecommendationAttributeValue;
					public static readonly DataTable ProductReview;
                    public static readonly DataTable ProductReviewAttributeValue;
                    public static readonly DataTable ProductReviewImage;
                    public static readonly DataTable ProductReviewVideo;
                    public static readonly DataTable ProductReviewThirdPartyRatingCounts;

					[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Reviewed.")]
					static Table()
					{
						ProductFeedback = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductFeedback.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
						ProductFeedback.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CultureId, typeof(int)));
						ProductFeedback.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.DateAdded, typeof(DateTime)));
						ProductFeedback.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CustomerId, typeof(Guid)));
						ProductFeedback.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CustomerName, typeof(string)));
						ProductFeedback.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CustomerLocation, typeof(string)));
						ProductFeedback.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.EditorComments, typeof(string)));

						ProductRating = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductRating.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
						ProductRating.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductRating.Value, typeof(byte)));

						ProductRatingAttributeValue = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductRatingAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
						ProductRatingAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductRatingAttributeValue.AttributeId, typeof(Guid)));
						ProductRatingAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductRatingAttributeValue.Value, typeof(byte)));

						ProductRecommendation = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductRecommendation.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
						ProductRecommendation.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductRecommendation.Value, typeof(bool)));

						ProductRecommendationAttributeValue = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductRecommendationAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
						ProductRecommendationAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductRecommendationAttributeValue.AttributeId, typeof(Guid)));
						ProductRecommendationAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductRecommendationAttributeValue.Value, typeof(bool)));

						ProductReview = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductReview.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
						ProductReview.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReview.Title, typeof(string)));
						ProductReview.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReview.Body, typeof(string)));

                        ProductReviewAttributeValue = new DataTable
                        {
                            Locale = CultureInfo.InvariantCulture
                        };
                        ProductReviewAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
                        ProductReviewAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewAttributeValue.AttributeId, typeof(Guid)));
                        ProductReviewAttributeValue.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewAttributeValue.Value, typeof(string)));

                        ProductReviewImage = new DataTable
                        {
                            Locale = CultureInfo.InvariantCulture
                        };
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImageId, typeof(Guid)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.Caption, typeof(string)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ThumbnailPath, typeof(string)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ThumbnailWidth, typeof(short)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ThumbnailHeight, typeof(short)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImagePath, typeof(string)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImageWidth, typeof(short)));
                        ProductReviewImage.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImageHeight, typeof(short)));

                        ProductReviewVideo = new DataTable
                        {
                            Locale = CultureInfo.InvariantCulture
                        };
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.StillPath, typeof(string)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.StillWidth, typeof(short)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.StillHeight, typeof(short)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.VideoPath, typeof(string)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.VideoWidth, typeof(short)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.VideoHeight, typeof(short)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.Length, typeof(short)));
                        ProductReviewVideo.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.Transcript, typeof(string)));

                        ProductReviewThirdPartyRatingCounts = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductReviewThirdPartyRatingCounts.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId, typeof(Guid)));
						ProductReviewThirdPartyRatingCounts.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewThirdPartyRatingCounts.TotalThirdPartyReviews, typeof(int)));
						ProductReviewThirdPartyRatingCounts.Columns.Add(new DataColumn(ProductFeedbackProvider.StoredProcedure.GetProductFeedback.ColumnName.ProductReviewThirdPartyRatingCounts.PositiveThirdPartyReviews, typeof(int)));
					}

				}

			}

		}

		#endregion // Inner Classes and Types

		#region Methods

		#region TestGetProductFeedback

		/// <summary>
		/// FIXME
		/// </summary>
		[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Reviewed.")]
		[TestMethod]
		public void TestGetProductFeedback()
		{
			DataTable feedbackResults;
			DataTable ratingResults;
			DataTable ratingAttributeValueResults;
			DataTable recommendationResults;
			DataTable recommendationAttributeValueResults;
			DataTable reviewResults;
            DataTable reviewAttributeValueResults;
            DataTable reviewImageResults;
            DataTable reviewVideoResults;
            DataTable reviewThirdPartyRatingCountsResults;
			DataTable[] results;
			DataTableReader reader;
			MockDatabaseCommandExecuteReaderReturns command;
			MockDatabaseConnection connection;
			MockDatabaseConnectionFactory connectionFactory;
			ProductFeedbackProvider provider;
			Dictionary<Guid, ProductFeedbackE> feedback;
			ProductFeedbackE feedbackE;

			feedbackResults = StoredProcedure.GetProductFeedback.Table.ProductFeedback.Clone();
			feedbackResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, TestConstants.CultureId.EnglishCanada, new DateTime(2008, 06, 01), TestConstants.CustomerId.MikeWhite, "Colin Coller", "Toronto, ON", null);
			feedbackResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback2, TestConstants.CultureId.FrenchCanada, new DateTime(2008, 07, 01), null, "John Doe", null, "Removed profanity.");

            // FIXME: BADGES

			ratingResults = StoredProcedure.GetProductFeedback.Table.ProductRating.Clone();
			ratingResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, (byte)5);

			ratingAttributeValueResults = StoredProcedure.GetProductFeedback.Table.ProductRatingAttributeValue.Clone();
			ratingAttributeValueResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductRatingAttribute.AttributeId.ImageQuality, (byte)5);
			ratingAttributeValueResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductRatingAttribute.AttributeId.SoundQuality, (byte)4);

			recommendationResults = StoredProcedure.GetProductFeedback.Table.ProductRecommendation.Clone();
			recommendationResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, true);

			recommendationAttributeValueResults = StoredProcedure.GetProductFeedback.Table.ProductRecommendationAttributeValue.Clone();
			recommendationAttributeValueResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductRecommendationAttribute.AttributeId.FamilyMember, false);
			recommendationAttributeValueResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductRecommendationAttribute.AttributeId.Friend, true);

			reviewResults = StoredProcedure.GetProductFeedback.Table.ProductReview.Clone();
			reviewResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, "Money very well spent!", "This product is excellent.  I'm very glad I spent money on it.  5 stars!");

            reviewAttributeValueResults = StoredProcedure.GetProductFeedback.Table.ProductReviewAttributeValue.Clone();
            reviewAttributeValueResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductReviewAttribute.AttributeId.Pros, "Very easy to use.");
            reviewAttributeValueResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductReviewAttribute.AttributeId.Cons, "Product documentation could be less vague.");

            reviewImageResults = StoredProcedure.GetProductFeedback.Table.ProductReviewImage.Clone();
            reviewImageResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductReviewImage.ImageId.ProductInSunlight, "Image 1", "/path/to/thumbnail/image1.gif", 25, 30, "/path/to/full/image1.gif", 250, 300);
            reviewImageResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, Constants.ProductReviewImage.ImageId.ProuctInLowLight, "Image 2", "/path/to/thumbnail/image2.gif", 50, 40, "/path/to/full/image2.gif", 500, 400);

            reviewVideoResults = StoredProcedure.GetProductFeedback.Table.ProductReviewVideo.Clone();
            reviewVideoResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, "/path/to/still/video1.gif", 60, 40, "/path/to/video/video1.flv", 300, 200, 60, "This is my review...");
            reviewVideoResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, "/path/to/still/video2.gif", 50, 40, "/path/to/video/video2.flv", 250, 200, 120, null);

            reviewThirdPartyRatingCountsResults = StoredProcedure.GetProductFeedback.Table.ProductReviewThirdPartyRatingCounts.Clone();
			reviewThirdPartyRatingCountsResults.Rows.Add(Constants.ProductFeedback.FeedbackId.Feedback1, 5, 4);

			results = new DataTable[]
			{
				feedbackResults,
                new DataTable() { Locale = new CultureInfo("en-CA") }, // FIXME: BADGES
				ratingResults,
				ratingAttributeValueResults,
				recommendationResults,
				recommendationAttributeValueResults,
				reviewResults,
				reviewAttributeValueResults,
                reviewImageResults,
                reviewVideoResults,
				reviewThirdPartyRatingCountsResults,
			};

			reader = new DataTableReader(results);

			command = new MockDatabaseCommandExecuteReaderReturns(ProductFeedbackProvider.DatabaseSchema, ProductFeedbackProvider.StoredProcedure.GetProductFeedback.CommandName, 3, reader);

			connection = new MockDatabaseConnection(command.Object);

			connectionFactory = new MockDatabaseConnectionFactory(TestConstants.TenantId.JTLeigh, ProductFeedbackProvider.DatabaseKeyReadOperations, connection.Object);

			provider = new ProductFeedbackProvider()
			{
				DatabaseConnectionFactory = connectionFactory.Object,
			};

            feedback = provider.GetProductFeedback(TestConstants.TenantId.JTLeigh, "BaseCatalog", "123");

			Assert.IsNotNull(feedback);

			Assert.AreEqual(2, feedback.Count);

			Assert.IsTrue(feedback.TryGetValue(Constants.ProductFeedback.FeedbackId.Feedback1, out feedbackE));
			Assert.AreEqual(Constants.ProductFeedback.FeedbackId.Feedback1, feedbackE.FeedbackId);
			Assert.AreEqual(TestConstants.CultureId.EnglishCanada, feedbackE.CultureId);
			Assert.AreEqual(new DateTime(2008, 06, 01), feedbackE.DateAdded);
			Assert.AreEqual(TestConstants.CustomerId.MikeWhite, feedbackE.CustomerId);
			Assert.AreEqual("Colin Coller", feedbackE.CustomerName);
			Assert.AreEqual("Toronto, ON", feedbackE.CustomerLocation);
			Assert.IsNull(feedbackE.EditorComments);
			Assert.AreEqual(Constants.ProductFeedback.FeedbackId.Feedback1, feedbackE.Rating.FeedbackId);
			Assert.AreEqual((byte)5, feedbackE.Rating.Value);
			Assert.IsNotNull(feedbackE.Rating.AttributeValues); // FIXME: Finish implementing this.
			Assert.AreEqual(Constants.ProductFeedback.FeedbackId.Feedback1, feedbackE.Recommendation.FeedbackId);
			Assert.AreEqual(true, feedbackE.Recommendation.Value);
			Assert.IsNotNull(feedbackE.Recommendation.AttributeValues); // FIXME: Finish implementing this.
			Assert.AreEqual(Constants.ProductFeedback.FeedbackId.Feedback1, feedbackE.Review.FeedbackId);
			Assert.AreEqual("Money very well spent!", feedbackE.Review.Title);
			Assert.AreEqual("This product is excellent.  I'm very glad I spent money on it.  5 stars!", feedbackE.Review.Body);
			Assert.AreEqual(5, feedbackE.Review.TotalThirdPartyReviews);
			Assert.AreEqual(4, feedbackE.Review.PositiveThirdPartyReviews);
			Assert.IsNotNull(feedbackE.Review.AttributeValues); // FIXME: Finish implementing this.
            Assert.IsNotNull(feedbackE.Review.Images); // FIXME: Finish implementing this.

			Assert.IsTrue(feedback.TryGetValue(Constants.ProductFeedback.FeedbackId.Feedback2, out feedbackE));
			Assert.AreEqual(Constants.ProductFeedback.FeedbackId.Feedback2, feedbackE.FeedbackId);
			Assert.AreEqual(TestConstants.CultureId.FrenchCanada, feedbackE.CultureId);
			Assert.AreEqual(new DateTime(2008, 07, 01), feedbackE.DateAdded);
			Assert.IsNull(feedbackE.CustomerId);
			Assert.AreEqual("John Doe", feedbackE.CustomerName);
			Assert.IsNull(feedbackE.CustomerLocation);
			Assert.AreEqual("Removed profanity.", feedbackE.EditorComments);
			Assert.IsNull(feedbackE.Rating);
			Assert.IsNull(feedbackE.Recommendation);
            Assert.IsNull(feedbackE.Review);
        }

		#endregion // TestGetProductFeedback

		#endregion // Methods

	}

}
